#!/bin/bash

# ========== 基本配置 ==========
DEVICE_NAME="主服务器"
NET_DEVICE="m-ms-main"                   # 网络设备
MAX_UPLOAD_SPEED="40"                    # Mbps（最大上行速率）

SERVICE_START="17:00"                    # 服务开始时间
SERVICE_END="23:20"                      # 服务结束时间
MANUAL_LIMIT_START="19:00"               # 人为限速开始时间
MANUAL_LIMIT_END="20:40"                 # 人为限速结束时间

CHECK_INTERVAL="300"                     # 检测间隔（秒，默认5分钟）
SAMPLE_INTERVAL="3"                      # 每次采样间隔（秒）
THRESHOLD_PERCENT="80"                   # 阈值比例
THRESHOLD=$((MAX_UPLOAD_SPEED * THRESHOLD_PERCENT / 100))

PASS_RATE_LIMIT=30                       # 通过率阈值，默认30%
CONSECUTIVE_FAIL_LIMIT=2                 # 连续不通过次数上限
COOLDOWN=3600                            # 重启冷却时间（秒）
STARTUP_DELAY=120                        # 重启后延迟检测时间（秒）

SERVERCHAN_KEY=""                        # Server酱 SendKey（可选）

LOG_DIR="/var/log/network_monitor"
STATE_DIR="/var/lib/network_monitor"
LOG_FILE="$LOG_DIR/network_monitor.log"
STATE_FILE="$STATE_DIR/last_reboot_time"
COUNT_FILE="$STATE_DIR/reboot_count"
mkdir -p "$LOG_DIR" "$STATE_DIR"

# 日志大小上限（字节），默认1MB
MAX_LOG_SIZE=$((1024*1024))

# ========== 日志函数 ==========
log() {
    echo "[$(date '+%F %T')] $1" | tee -a "$LOG_FILE"
}

# ========== 日志清理 ==========
rotate_log_if_needed() {
    if [ -f "$LOG_FILE" ] && [ $(stat -c%s "$LOG_FILE") -gt $MAX_LOG_SIZE ]; then
        local rotated="${LOG_FILE}.$(date +%F-%H%M%S).gz"
        gzip -c "$LOG_FILE" > "$rotated"
        echo "[$(date '+%F %T')] ⚠️ 日志过大，已轮转到 $rotated" > "$LOG_FILE"
    fi
}

# ========== 服务时间检查 ==========
is_within_service_time() {
    local now=$(date +%H:%M)
    [[ "$now" > "$SERVICE_START" && "$now" < "$SERVICE_END" ]]
}

# ========== 人为限速时间检查 ==========
is_in_manual_limit() {
    local now=$(date +%H:%M)
    [[ "$now" > "$MANUAL_LIMIT_START" && "$now" < "$MANUAL_LIMIT_END" ]]
}

# ========== 网络速度检测 ==========
check_upload_speed() {
    local start_bytes end_bytes diff bits speed
    start_bytes=$(cat /sys/class/net/$NET_DEVICE/statistics/tx_bytes)
    sleep $SAMPLE_INTERVAL
    end_bytes=$(cat /sys/class/net/$NET_DEVICE/statistics/tx_bytes)
    diff=$((end_bytes - start_bytes))
    bits=$((diff * 8))
    speed=$((bits / SAMPLE_INTERVAL / 1000000))   # Mbps
    echo "$speed"
}

# ========== 通知 ==========
notify_reboot() {
    local max_speed=$1
    local last_speed=$2
    local reboot_count=$3
    local pass_rate_prev=$4
    local pass_rate_now=$5

    local msg="⚠️ 网络异常重启通知
🖥 设备: ${DEVICE_NAME}
🌐 网络设备: ${NET_DEVICE}
📈 最大上行: ${MAX_UPLOAD_SPEED} Mbps
🚦 阈值: ${THRESHOLD} Mbps
⚡ 最近速度: ${last_speed} Mbps
📊 检测最大速度: ${max_speed} Mbps
✅ 上次通过率: ${pass_rate_prev}%
❌ 本次通过率: ${pass_rate_now}%
🔄 今日重启次数: ${reboot_count}"

    log "$msg"

    if [[ -n "$SERVERCHAN_KEY" ]]; then
        # URL encode 换行符为 %0A 保持整齐
        local msg_encoded=$(echo "$msg" | sed 's/$/%0A/' | tr -d '\n')
        curl -s "https://sctapi.ftqq.com/${SERVERCHAN_KEY}.send" \
            -d "title=⚠️ 网络重启通知" \
            -d "desp=$msg_encoded" >/dev/null
    fi
}

# ========== 初始化状态 ==========
fail_count=0
today=$(date +%F)
pass_rate_prev=0

# 读取上次重启时间
if [ -f "$STATE_FILE" ]; then
    last_reboot_time=$(cat "$STATE_FILE")
else
    last_reboot_time=0
fi

# 读取今日重启次数
if [ -f "$COUNT_FILE" ]; then
    stored_day=$(head -n1 "$COUNT_FILE")
    stored_count=$(tail -n1 "$COUNT_FILE")
    if [[ "$stored_day" == "$today" ]]; then
        reboot_count=$stored_count
    else
        reboot_count=0
    fi
else
    reboot_count=0
fi

# ========== 启动信息 ==========
log "=== 网络监控系统启动 ==="
log "设备: $DEVICE_NAME"
log "网络设备: $NET_DEVICE"
log "最大上行: ${MAX_UPLOAD_SPEED}Mbps"
log "阈值: ${THRESHOLD}Mbps"
log "服务时间: ${SERVICE_START}-${SERVICE_END}"
log "人为限速: ${MANUAL_LIMIT_START}-${MANUAL_LIMIT_END}"
log "检测间隔: ${CHECK_INTERVAL}秒"
log "重启策略: 连续${CONSECUTIVE_FAIL_LIMIT}次失败 & ${COOLDOWN}s 冷却"

# 重启后延迟检测
log "⚠️ 重启后等待 ${STARTUP_DELAY} 秒再开始检测..."
sleep $STARTUP_DELAY

# ========== 主循环 ==========
while true; do
    rotate_log_if_needed

    # 服务时间检查
    if ! is_within_service_time; then
        log "⏸ 不在服务时间，跳过检测"
        sleep "$CHECK_INTERVAL"
        continue
    fi

    # 人为限速时间检查
    if is_in_manual_limit; then
        log "⏸ 当前处于人为限速时间 (${MANUAL_LIMIT_START}-${MANUAL_LIMIT_END})，跳过检测"
        sleep "$CHECK_INTERVAL"
        continue
    fi

    log "开始检测：阈值=${THRESHOLD}Mbps，区间=${CHECK_INTERVAL}s"
    pass_count=0
    max_speed=0
    sample_count=$((CHECK_INTERVAL / SAMPLE_INTERVAL))

    for ((i=0; i<sample_count; i++)); do
        speed=$(check_upload_speed)
        [[ $speed -gt $max_speed ]] && max_speed=$speed
        if [[ $speed -ge $THRESHOLD ]]; then
            pass_count=$((pass_count+1))
            log "✅ 样本#$i: ${speed}Mbps ≥ ${THRESHOLD}Mbps  (累计: $pass_count/$((i+1)))"
        else
            log "❌ 样本#$i: ${speed}Mbps < ${THRESHOLD}Mbps  (累计: $pass_count/$((i+1)))"
        fi
    done

    # 计算通过率
    pass_rate_now=$((pass_count * 100 / sample_count))

    # 判定结果
    if [[ $pass_rate_now -ge $PASS_RATE_LIMIT ]]; then
        log "检测结果：✅ 通过 (达标=$pass_count/$sample_count, 通过率=${pass_rate_now}%)"
        fail_count=0
    else
        log "检测结果：❌ 不通过 (达标=$pass_count/$sample_count, 通过率=${pass_rate_now}%)"
        fail_count=$((fail_count+1))
    fi

    # 连续失败触发重启
    if [[ $fail_count -ge $CONSECUTIVE_FAIL_LIMIT ]]; then
        now=$(date +%s)
        if (( now - last_reboot_time >= COOLDOWN )); then
            log "⚠️ 连续${fail_count}次不通过，执行重启！（通过率=${pass_rate_now}%）"
            fail_count=0

            # 当天重启计数
            current_day=$(date +%F)
            if [[ "$today" != "$current_day" ]]; then
                today=$current_day
                reboot_count=0
            fi
            reboot_count=$((reboot_count+1))

            last_reboot_time=$now
            echo "$last_reboot_time" > "$STATE_FILE"
            echo "$today" > "$COUNT_FILE"
            echo "$reboot_count" >> "$COUNT_FILE"

            notify_reboot "$max_speed" "$speed" "$reboot_count" "$pass_rate_prev" "$pass_rate_now"
            reboot
        else
            log "⚠️ 冷却期中，跳过重启（剩余$((COOLDOWN - (now - last_reboot_time)))秒）"
        fi
    fi

    pass_rate_prev=$pass_rate_now
    sleep "$CHECK_INTERVAL"
done
